import {_decorator, Component, Node, Prefab, instantiate, NodePool} from 'cc';

/**
 * 节点池
 */
export class PoolManager {
    /**
     * 节点池缓存
     */
    private nodePoolCache: Map<string, NodePool> = new Map<string, NodePool>();
    /**
     * 预制体缓存
     */
    private prefabCache: Map<string, Prefab> = new Map<string, Prefab>();
    /**
     * 节点池实例
     */
    private static INSTANCE: PoolManager = null;

    /**
     * 获取节点池实例
     */
    public static getInstance(): PoolManager {
        if (!this.INSTANCE) {
            this.INSTANCE = new PoolManager();
        }
        return this.INSTANCE;
    }

    /**
     * 禁止外部创建对象
     */
    private constructor() {
    }

    /**
     * 获取节点
     *
     * @param prefab 预制体
     * @param parent 父节点
     */
    public getNode(prefab: Prefab, parent: Node): Node {
        // 预制体名称为key
        const key = prefab.name;
        // 缓存预制体
        this.prefabCache.set(key, prefab);

        // 节点
        let node: Node;
        // 当有缓存时
        if (this.nodePoolCache.has(key)) {
            // 获取节点池
            const nodePool = this.nodePoolCache.get(key);
            if (nodePool.size() > 0) {
                // 返回节点池里的节点
                node = nodePool.get();
            } else {
                // 实例化节点
                node = instantiate(prefab);
            }
        } else {
            // 没有缓存
            // 创建节点池
            const nodePool = new NodePool();
            // 存入节点池存入节点池缓存
            this.nodePoolCache.set(key, nodePool);
            // 实例化节点
            node = instantiate(prefab);
        }

        // 设置父节点
        node.setParent(parent);
        // 激活节点
        node.active = true;
        // 返回节点
        return node;
    }

    /**
     * 回收节点
     * 核心：将节点的 parent 设置为 null
     *
     * @param node 节点
     */
    public putNode(node: Node) {
        // 节点名称为key
        const key = node.name;

        // 回收节点
        node.setParent(null);

        // 节点池
        let nodePool: NodePool;
        // 当有缓存时
        if (this.nodePoolCache.has(key)) {
            // 获取节点池
            nodePool = this.nodePoolCache.get(key);
        } else {
            // 当没有缓存时
            nodePool = new NodePool();
            // 将节点池存入节点池缓存中
            this.nodePoolCache.set(key, nodePool);
        }

        // 将节点存入节点池
        nodePool.put(node);
    }
}